package edu.hda.pt.server.connections;

import java.net.InetSocketAddress;
import java.util.concurrent.Executors;

import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;

import edu.hda.pt.server.PTServer;
import edu.hda.pt.server.connections.netty.ServerPipelineFactory;
import edu.hda.pt.server.connections.netty.StreamThread;
import edu.hda.pt.utils.Stream;
import edu.hda.pt.utils.Stream.StreamState;
import edu.hda.pt.utils.connections.netty.NettyConstants;

/**
 * Server implementation for the connection method JBoss Netty
 * 
 * @author Marc Hammerton
 * 
 */
public class PTServerNetty extends PTServer {

	private ServerBootstrap bootstrap;
	private StreamThread st;

	/**
	 * @see edu.hda.pt.server.PTServer#start()
	 */
	@Override
	public void start() {
		ChannelFactory factory = new NioServerSocketChannelFactory(Executors
				.newCachedThreadPool(), Executors.newCachedThreadPool());

		bootstrap = new ServerBootstrap(factory);
		bootstrap.setPipelineFactory(new ServerPipelineFactory(this));

		// Bind and start to accept incoming connections.
		bootstrap.bind(new InetSocketAddress(NettyConstants.PORT));

		st = new StreamThread();
		st.start();

	}

	/**
	 * @see edu.hda.pt.server.PTServer#stop()
	 */
	@Override
	public void stop() {
	}

	/**
	 * Method for handling stream requests. If a new stream request is received,
	 * it is added to the
	 * {@link edu.hda.pt.server.connections.netty.StreamThread}, which then
	 * starts sending frames to the client. When a client requests the stream to
	 * be stopped, the client is removed from the
	 * {@link edu.hda.pt.server.connections.netty.StreamThread}
	 * 
	 * @param stream
	 *            - The stream object with information about the request
	 * @param channel
	 *            - The channel with information about the client connection
	 * @return The stream object containing the information about the stream
	 *         state
	 */
	public Stream handleStream(Stream stream, Channel channel) {

		if (stream.getState() == StreamState.START) {
			// Init StreamThread
			if (st.getFileSize() == 0) {
				synchronized (st) {
					st.setFileSize(stream.getFs());
					st.addChannel(channel);
					st.notify();
				}

			} else if (stream.getFs() == st.getFileSize()) {
				synchronized (st) {
					st.addChannel(channel);
				}
			}
			stream.setState(StreamState.RUNNING);

		} else if (stream.getState() == StreamState.FINISH) {
			st.removeChannel(channel);
			System.out.println(channel + ": streaming stopped");
			stream.setState(StreamState.STOPPED);
		}

		return stream;
	}

}
